import L, {
  DomUtil,
  DomEvent,
  Popup,
  LatLng,
  toLatLng,
  Util,
  toPoint,
  Icon,
  Point,
  Polyline,
} from "leaflet";

const LabelLinePopup = Popup.extend({
  options: {
    autoClose: false,
    closeOnEscapeKey: true,
    closeOnClick: false,
    // icon: new Icon.Default(),
  },
  initialize(options, source) {
    const filteredOptions = {
      ...options,
      closeButton: false,
      // line: new Polyline()
    };

    if (options instanceof LatLng || Array.isArray(options)) {
      this._latlng = toLatLng(options);
      Util.setOptions(this, source);
    } else {
      Util.setOptions(this, filteredOptions);
      this._source = source;
    }
    if (this.options.content) {
      this._content = this.options.content;
    }
  },
  _initLayout() {
    this._polyline = L.polyline([], { color: "red", weight: 2 }).addTo(
      this._map
    );

    const prefix = "leaflet-popup";
    const container = (this._container = DomUtil.create(
      "div",
      `${prefix} ${this.options.className || ""} leaflet-zoom-animated`
    ));

    this._contentNode = DomUtil.create("div", ``, container);

    if (this.options.trackResize) {
      this._resizeObserver = new ResizeObserver((entries) => {
        if (!this._map) {
          return;
        }
        this._containerWidth = entries[0]?.contentRect?.width;
        this._containerHeight = entries[0]?.contentRect?.height;

        this._updateLayout();
        this._updatePosition();
        this._adjustPan();
      });

      this._resizeObserver.observe(this._contentNode);
    }

    this._updatePolylineLatLngs();
  },

  _updatePolylineLatLngs() {
    if (!this._map || !this._latlng) return;

    const pos = this._map.latLngToLayerPoint(this._latlng);
    const offset = this.options.offset || L.point(0, 0);

    // 计算弹出框位置
    const popupPoint = pos.add(offset);
    const popupLatLng = this._map.containerPointToLatLng(popupPoint);

    // 计算中间点（纬度相同，经度取中点）
    const midLatLng = L.latLng(45, 180);

    // 设置折线的坐标点：起点 -> 中间点（水平）-> 终点
    this._polyline.setLatLngs([popupLatLng, midLatLng, this._latlng]);
  },

  _updateLayout() {
    const container = this._contentNode,
      style = container.style;

    style.width = "";
    style.whiteSpace = "nowrap";

    style.maxWidth = `${this.options.maxWidth}px`;
    style.minWidth = `${this.options.minWidth}px`;
    style.whiteSpace = "";

    style.height = "";

    const height = this._containerHeight ?? container.offsetHeight,
      maxHeight = this.options.maxHeight,
      scrolledClass = "leaflet-popup-scrolled";

    if (maxHeight && height > maxHeight) {
      style.height = `${maxHeight}px`;
      container.classList.add(scrolledClass);
    } else {
      container.classList.remove(scrolledClass);
    }

    this._containerWidth = this._container.offsetWidth;
    this._containerHeight = this._container.offsetHeight;
  },

  _updatePosition() {
    if (!this._map) {
      return;
    }

    const pos = this._map.latLngToLayerPoint(this._latlng),
      anchor = this._getAnchor();
    let offset = this.options.offset;

    if (this._zoomAnimated) {
      DomUtil.setPosition(this._container, pos.add(anchor));
    } else {
      offset = offset.add(pos).add(anchor);
    }

    const bottom = (this._containerBottom = -offset.y),
      left = (this._containerLeft =
        -Math.round(this._containerWidth / 2) + offset.x);

    // bottom position the overlay in case the height of the overlay changes (images loading etc)
    this._container.style.bottom = `${bottom}px`;
    this._container.style.left = `${left}px`;
  },
  _animateZoom(e) {
    const pos = this._map._latLngToNewLayerPoint(
        this._latlng,
        e.zoom,
        e.center
      ),
      anchor = this._getAnchor();
    DomUtil.setPosition(this._container, pos.add(anchor));
    this._updatePolylineLatLngs();
  },
  _updateContent() {
    if (!this._content) {
      return;
    }

    const node = this._contentNode;
    const content =
      typeof this._content === "function"
        ? this._content(this._source ?? this)
        : this._content;

    if (typeof content === "string") {
      node.innerHTML = content;
    } else {
      while (node.hasChildNodes()) {
        node.removeChild(node.firstChild);
      }
      node.appendChild(content);
    }

    // @namespace DivOverlay
    // @section DivOverlay events
    // @event contentupdate: Event
    // Fired when the content of the overlay is updated
    this.fire("contentupdate");
  },
});

L.labelLinePopup = function (options, source) {
  return new LabelLinePopup(options, source);
};
